package cn.fresh.xuanyuan.module.product.service.spu;

import cn.fresh.xuanyuan.framework.common.pojo.PageParam;
import cn.fresh.xuanyuan.module.infra.api.column.ColumnProductApi;
import cn.fresh.xuanyuan.module.member.api.level.dto.MemberLevelRespDTO;
import cn.fresh.xuanyuan.module.member.api.user.MemberUserApi;
import cn.fresh.xuanyuan.module.member.vo.MemberCollectVO;
import cn.fresh.xuanyuan.module.member.vo.MemberLikeVO;
import cn.fresh.xuanyuan.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.fresh.xuanyuan.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
import cn.fresh.xuanyuan.module.product.controller.admin.spu.vo.*;
import cn.fresh.xuanyuan.module.product.controller.app.property.vo.value.AppProductPropertyValueDetailRespVO;
import cn.fresh.xuanyuan.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
import cn.fresh.xuanyuan.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
import cn.fresh.xuanyuan.module.product.dal.dataobject.category.ProductCategoryDO;
import cn.fresh.xuanyuan.module.product.dal.dataobject.orchard.OrchardDO;
import cn.fresh.xuanyuan.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.fresh.xuanyuan.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.fresh.xuanyuan.module.product.dal.mysql.orchard.OrchardMapper;
import cn.fresh.xuanyuan.module.product.dal.mysql.spu.ProductSpuMapper;
import cn.fresh.xuanyuan.module.product.dto.WxQuerySpuDto;
import cn.fresh.xuanyuan.module.product.service.brand.ProductBrandService;
import cn.fresh.xuanyuan.module.product.service.category.ProductCategoryService;
import cn.fresh.xuanyuan.module.product.service.history.ProductBrowseHistoryService;
import cn.fresh.xuanyuan.module.product.service.sku.ProductSkuService;
import cn.fresh.xuanyuan.module.product.vo.plate.RankingListVo;
import cn.fresh.xuanyuan.module.product.vo.plate.WxProductVo;
import cn.fresh.xuanyuan.module.trade.api.cart.CartApi;
import cn.fresh.xuanyuan.module.trade.api.cart.dto.CartDto;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.fresh.xuanyuan.framework.common.enums.CommonStatusEnum;
import cn.fresh.xuanyuan.framework.common.pojo.PageResult;
import cn.fresh.xuanyuan.framework.common.util.collection.CollectionUtils;
import cn.fresh.xuanyuan.framework.common.util.object.BeanUtils;
import cn.fresh.xuanyuan.module.product.enums.spu.ProductSpuStatusEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static cn.fresh.xuanyuan.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.fresh.xuanyuan.framework.common.util.collection.CollectionUtils.*;
import static cn.fresh.xuanyuan.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.fresh.xuanyuan.module.product.dal.dataobject.category.ProductCategoryDO.CATEGORY_LEVEL;
import static cn.fresh.xuanyuan.module.product.enums.ErrorCodeConstants.*;

/**
 * 商品 SPU Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class ProductSpuServiceImpl implements ProductSpuService {

    @Resource
    private ProductSpuMapper productSpuMapper;

    @Resource
    @Lazy // 循环依赖，避免报错
    private ProductSkuService productSkuService;
    @Resource
    private ProductBrandService brandService;
    @Resource
    private ProductCategoryService categoryService;

    @Resource
    private ProductBrowseHistoryService productBrowseHistoryService;

    @Resource
    private OrchardMapper orchardMapper;

    @Resource
    private CartApi cartApi;

    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private ColumnProductApi columnProductApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createSpu(ProductSpuSaveReqVO createReqVO) {
        // 校验分类、品牌
        validateCategory(createReqVO.getCategoryId());
        if(createReqVO.getBrandId() != null) {
            brandService.validateProductBrand(createReqVO.getBrandId());
        }

        // 校验 SKU
        List<ProductSkuSaveReqVO> skuSaveReqList = createReqVO.getSkus();
        productSkuService.validateSkuList(skuSaveReqList, createReqVO.getSpecType());

        ProductSpuDO spu = BeanUtils.toBean(createReqVO, ProductSpuDO.class);
        // 初始化 SPU 中 SKU 相关属性
        initSpuFromSkus(spu, skuSaveReqList);
        // 验证果园信息
        if(createReqVO.getOrchardId() != null) {
            OrchardDO orchard = orchardMapper.selectById(createReqVO.getOrchardId());
            if(orchard == null) {
                throw exception(ORCHARD_NOT_EXISTS);
            }
            spu.setOrchardId(orchard.getId());
            spu.setOrchardName(orchard.getName());
        }

        ProductCategoryDO categoryDO = categoryService.getCategory(createReqVO.getCategoryId());
        if(categoryDO != null && categoryDO.getParentId() != null && categoryDO.getParentId() != 0) {
            spu.setTopCategoryId(categoryDO.getParentId());
        }
        else {
            spu.setTopCategoryId(createReqVO.getCategoryId());
        }
        // 插入 SPU
        productSpuMapper.insert(spu);
        // 插入 SKU
        productSkuService.createSkuList(spu.getId(), skuSaveReqList);
        // 返回
        return spu.getId();
    }

    private void buildDescription(ProductSpuDO spu) {
        if(StringUtils.isNotBlank(spu.getDescription())) {
            String description = spu.getDescription().replaceAll("style=\"\"", "style=\"width:100%;height:auto;\"");
            spu.setDescription(description);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpu(ProductSpuSaveReqVO updateReqVO) {
        // 校验 SPU 是否存在
        validateSpuExists(updateReqVO.getId());
        // 校验分类、品牌
        validateCategory(updateReqVO.getCategoryId());
        if(updateReqVO.getBrandId() != null) {
            brandService.validateProductBrand(updateReqVO.getBrandId());
        }
        // 校验SKU
        List<ProductSkuSaveReqVO> skuSaveReqList = updateReqVO.getSkus();
        productSkuService.validateSkuList(skuSaveReqList, updateReqVO.getSpecType());

        // 更新 SPU
        ProductSpuDO updateObj = BeanUtils.toBean(updateReqVO, ProductSpuDO.class);
        initSpuFromSkus(updateObj, skuSaveReqList);
        ProductCategoryDO categoryDO = categoryService.getCategory(updateReqVO.getCategoryId());
        updateObj.setTopCategoryId(categoryDO.getParentId());
        // 验证果园信息
        if(updateReqVO.getOrchardId() != null) {
            OrchardDO orchard = orchardMapper.selectById(updateReqVO.getOrchardId());
            if(orchard == null) {
                throw exception(ORCHARD_NOT_EXISTS);
            }
            updateObj.setOrchardId(orchard.getId());
            updateObj.setOrchardName(orchard.getName());
        }
        buildDescription(updateObj);
        productSpuMapper.updateById(updateObj);
        // 批量更新 SKU
        productSkuService.updateSkuList(updateObj.getId(), updateReqVO.getSkus());

        //更新栏目内商品信息
        try {
            ProductSpuRespDTO productSpuRespDTO = new ProductSpuRespDTO();
            org.springframework.beans.BeanUtils.copyProperties(updateObj, productSpuRespDTO);
            columnProductApi.updateColumnProductInfo(productSpuRespDTO);
        }
        catch (Exception e) {
            log.error("update updateColumnProductInfo exception", e);
        }
    }

    /**
     * 基于 SKU 的信息，初始化 SPU 的信息
     * 主要是计数相关的字段，例如说市场价、最大最小价、库存等等
     *
     * @param spu  商品 SPU
     * @param skus 商品 SKU 数组
     */
    private void initSpuFromSkus(ProductSpuDO spu, List<ProductSkuSaveReqVO> skus) {
        // sku 单价最低的商品的价格
        spu.setPrice(getMinValue(skus, ProductSkuSaveReqVO::getPrice));
        // sku 单价最低的商品的市场价格
        spu.setMarketPrice(getMinValue(skus, ProductSkuSaveReqVO::getMarketPrice));
        // sku 单价最低的商品的成本价格
        spu.setCostPrice(getMinValue(skus, ProductSkuSaveReqVO::getCostPrice));
        // skus 库存总数
        spu.setStock(getSumValue(skus, ProductSkuSaveReqVO::getStock, Integer::sum));
        // 若是 spu 已有状态则不处理
        if (spu.getStatus() == null) {
            spu.setStatus(ProductSpuStatusEnum.DISABLE.getStatus()); // 默认状态为上架
            spu.setSalesCount(0); // 默认商品销量
            spu.setBrowseCount(0); // 默认商品浏览量
        }
    }

    /**
     * 校验商品分类是否合法
     *
     * @param id 商品分类编号
     */
    private void validateCategory(Long id) {
        categoryService.validateCategory(id);
        // 校验层级
//        if (categoryService.getCategoryLevel(id) < CATEGORY_LEVEL) {
//            throw exception(SPU_SAVE_FAIL_CATEGORY_LEVEL_ERROR);
//        }
    }

    @Override
    public List<ProductSpuDO> validateSpuList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        // 获得商品信息
        List<ProductSpuDO> list = productSpuMapper.selectBatchIds(ids);
        Map<Long, ProductSpuDO> spuMap = CollectionUtils.convertMap(list, ProductSpuDO::getId);
        // 校验
        ids.forEach(id -> {
            ProductSpuDO spu = spuMap.get(id);
            if (spu == null) {
                throw exception(SPU_NOT_EXISTS);
            }
            if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
                throw exception(SPU_NOT_ENABLE, spu.getName());
            }
        });
        return list;
    }

    @Override
    public void updateBrowseCount(Long id, int incrCount) {
        productSpuMapper.updateBrowseCount(id , incrCount);
    }

    @Override
    public PageResult<ProductSpuRespVO> getListForPlate(String name, Long id, PageParam pageParam) {
        PageResult<ProductSpuDO> pageResult = productSpuMapper.getListForPlate(name, id, pageParam);
        return BeanUtils.toBean(pageResult, ProductSpuRespVO.class);
    }

    @Override
    public PageResult<ProductSpuRespVO> getSpuSelectForPlate(String name, Long id, Integer columnId, PageParam pageParam) {
        List<Long> spuIds = productSpuMapper.getSpuIdsFromPlate(columnId);
        PageResult<ProductSpuDO> pageResult = productSpuMapper.getSpuSelectForPlate(name, id, spuIds, pageParam);
        return BeanUtils.toBean(pageResult, ProductSpuRespVO.class);
    }

    @Override
    public PageResult<WxProductVo> getWxProductList(WxQuerySpuDto wxQuery, Long userId) {
        Page<WxProductVo> page = PageHelper.startPage(wxQuery.getPageNo(), wxQuery.getPageSize());
        List<WxProductVo> list = productSpuMapper.getWxProductList(wxQuery.getColumnId(), wxQuery.getKeyword(), wxQuery.getCategoryId());
        PageResult<WxProductVo> pageResult = new PageResult<>();
        if(CollectionUtil.isNotEmpty(list)) {
            for(WxProductVo p : list) {
                p.setProductId(p.getId());
                p.setSingle(false);
                p.setIsLike(false);
                p.setIsCollect(false);
                if(StringUtils.isNotBlank(p.getProperties())) {
                    JSONArray skus  = JSON.parseArray(p.getProperties());
                    StringBuilder sku = new StringBuilder();
                    if(skus != null && !skus.isEmpty()) {
                        for(int i = 0; i < skus.size(); i++) {
                            JSONObject json = skus.getJSONObject(i);
                            sku.append(json.getString("valueName"));
                            if(i < (skus.size() - 1)) {
                                sku.append("、");
                            }
                        }
                        if(skus.size() == 1) {
                            p.setSingle(true);
                        }
                    }
                    p.setSku(sku.toString());
                }
                if(StringUtils.isNotBlank(p.getSliderList())) {
                    List<String> carousel = JSON.parseArray(p.getSliderList(), String.class);
                    if(CollectionUtil.isNotEmpty(carousel) && carousel.size() > 3) {
                        carousel = carousel.subList(0,3);
                    }
                    p.setCarousel(carousel);
                }
                if(p.getMarketPrice() != null) {
                    BigDecimal price = new BigDecimal(p.getMarketPrice()).divide(new BigDecimal(100));
                    p.setPrice(price);
                }
                if(p.getProductPrice() != null) {
                    BigDecimal price = new BigDecimal(p.getProductPrice()).divide(new BigDecimal(100));
                    p.setPayPrice(price);
                }
                userAttrBuildHandle(p, userId);
            }
            //处理特殊属性
//            list.forEach(p -> {
//
//            });
        }

        pageResult.setList(list);
        pageResult.setTotal(page.getTotal());
        return pageResult;
    }

    private void userAttrBuildHandle(WxProductVo product, Long userId) {
        try {
            if(userId != null) {
                MemberLikeVO likeVO = memberUserApi.isLike(userId, product.getProductId()).getCheckedData();
                if(likeVO != null) {
                    product.setIsLike(true);
                }
                MemberCollectVO collectVO = memberUserApi.isCollect(userId, product.getProductId()).getCheckedData();
                if(collectVO != null) {
                    product.setIsCollect(true);
                }
            }
        }
        catch (Exception e) {
            log.error("userAttrBuildHandle exception:", e);
        }
    }

    @Override
    public PageResult<WxProductVo> wxSearch(String keyword, PageParam pageParam) {
        Page<ProductSpuDO> page = PageHelper.startPage(pageParam.getPageNo(), pageParam.getPageSize());
        List<WxProductVo> list = productSpuMapper.wxSearch(keyword);
        PageResult<WxProductVo> pageResult = new PageResult<>();
        if(CollectionUtil.isNotEmpty(list)) {
            //处理特殊属性
            list.forEach(p -> {
                p.setProductId(p.getId());
                if(StringUtils.isNotBlank(p.getProperties())) {
                    JSONArray skus  = JSON.parseArray(p.getProperties());
                    JSONObject json = skus.getJSONObject(0); //取一个
                    String sku = json.getString("propertyName") + "：" + json.getString("valueName");
                    p.setSku(sku);
                }
                if(StringUtils.isNotBlank(p.getSliderList())) {
                    List<String> carousel = JSON.parseArray(p.getSliderList(), String.class);
                    p.setCarousel(carousel);
                }
                if(p.getMarketPrice() != null) {
                    BigDecimal price = new BigDecimal(p.getMarketPrice()).divide(new BigDecimal(100));
                    p.setPrice(price);
                }
                if(p.getProductPrice() != null) {
                    BigDecimal price = new BigDecimal(p.getProductPrice()).divide(new BigDecimal(100));
                    p.setPayPrice(price);
                }
            });
        }

        pageResult.setList(list);
        pageResult.setTotal(page.getTotal());
        return pageResult;
    }

    @Override
    public AppProductSpuDetailRespVO getProductDetail(Long id, Long userID) {
        ProductSpuDO spu = getSpu(id);
        if (spu == null) {
            throw exception(SPU_NOT_EXISTS);
        }
        if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) {
            throw exception(SPU_NOT_ENABLE);
        }
        // 获得商品 SKU
        List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());

        // 增加浏览量
        updateBrowseCount(id, 1);
        // 保存浏览记录
        productBrowseHistoryService.createBrowseHistory(getLoginUserId(), id);

        // 拼接返回
        spu.setBrowseCount(spu.getBrowseCount() + spu.getVirtualSalesCount());
        AppProductSpuDetailRespVO spuVO = BeanUtils.toBean(spu, AppProductSpuDetailRespVO.class)
                .setSkus(BeanUtils.toBean(skus, AppProductSpuDetailRespVO.Sku.class));
        if(spu.getOrchardId() != null) {
            OrchardDO orchard = orchardMapper.selectById(spu.getOrchardId());
            if(orchard != null) {
                String area = orchard.getProvince() + orchard.getCity();
                spuVO.setProducingArea(area);
            }
        }

        // 转换价格
        if(spu.getMarketPrice() != null) {
            BigDecimal price = new BigDecimal(spu.getMarketPrice()).divide(new BigDecimal(100));
            spuVO.setSalePrice(price);
        }
        if(spu.getPrice() != null) {
            BigDecimal price = new BigDecimal(spu.getPrice()).divide(new BigDecimal(100));
            spuVO.setPayPrice(price);
        }
        return spuVO;
    }

    @Override
    public List<RankingListVo> getRankingList() {
        List<RankingListVo> data = new ArrayList<>();
        List<WxProductVo> list = productSpuMapper.getSaleTop();
        if(CollectionUtil.isNotEmpty(list)) {
            for(int i = 0; i < list.size(); i++) {
                WxProductVo p = list.get(i);
                RankingListVo rank = new RankingListVo();
                rank.setIndex(i + 1);
                rank.setProductName(p.getProductName());
                rank.setProductId(p.getId());
                if(p.getSaleTotal() == null || p.getSaleTotal() <= 0) {
                    p.setSaleTotal(1);
                }
                rank.setSaleNum(p.getSaleTotal());
                data.add(rank);
            }
        }
        return data;
    }

    @Override
    public void addLike(Long id) {
        productSpuMapper.addLike(id);
    }

    @Override
    public void addCollect(Long id) {
        productSpuMapper.addCollect(id);
    }

    @Override
    public void subLike(Long id) {
        productSpuMapper.subLike(id);
    }

    @Override
    public void subCollect(Long id) {
        productSpuMapper.subCollect(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSpu(Long id) {
        // 校验存在
        validateSpuExists(id);
        // 校验商品状态不是回收站不能删除
        ProductSpuDO spuDO = productSpuMapper.selectById(id);
        // 判断 SPU 状态是否为回收站
        if (ObjectUtil.notEqual(spuDO.getStatus(), ProductSpuStatusEnum.RECYCLE.getStatus())) {
            throw exception(SPU_NOT_RECYCLE);
        }
        // TODO 芋艿：【可选】参与活动中的商品，不允许删除？？？

        // 删除 SPU
        productSpuMapper.deleteById(id);
        // 删除关联的 SKU
        productSkuService.deleteSkuBySpuId(id);
    }

    private void validateSpuExists(Long id) {
        if (productSpuMapper.selectById(id) == null) {
            throw exception(SPU_NOT_EXISTS);
        }
    }

    @Override
    public ProductSpuDO getSpu(Long id) {
        return productSpuMapper.selectById(id);
    }

    @Override
    public List<ProductSpuDO> getSpuList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return productSpuMapper.selectBatchIds(ids);
    }

    @Override
    public List<ProductSpuDO> getSpuListByIds(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<Long> list = new ArrayList<>(ids);
        return productSpuMapper.selectByIds(list);
    }

    @Override
    public List<ProductSpuDO> getSpuListByStatus(Integer status) {
        return productSpuMapper.selectList(ProductSpuDO::getStatus, status);
    }

    @Override
    public PageResult<ProductSpuDO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
        return productSpuMapper.selectPage(pageReqVO);
    }

    @Override
    public PageResult<ProductSpuDO> getSpuPage(AppProductSpuPageReqVO pageReqVO) {
        // 查找时，如果查找某个分类编号，则包含它的子分类。因为顶级分类不包含商品
        Set<Long> categoryIds = new HashSet<>();
        if (pageReqVO.getCategoryId() != null && pageReqVO.getCategoryId() > 0) {
            categoryIds.add(pageReqVO.getCategoryId());
            List<ProductCategoryDO> categoryChildren = categoryService.getCategoryList(new ProductCategoryListReqVO()
                    .setStatus(CommonStatusEnum.ENABLE.getStatus()).setParentId(pageReqVO.getCategoryId()));
            categoryIds.addAll(convertList(categoryChildren, ProductCategoryDO::getId));
        }
        if (CollUtil.isNotEmpty(pageReqVO.getCategoryIds())) {
            categoryIds.addAll(pageReqVO.getCategoryIds());
            List<ProductCategoryDO> categoryChildren = categoryService.getCategoryList(new ProductCategoryListReqVO()
                    .setStatus(CommonStatusEnum.ENABLE.getStatus()).setParentIds(pageReqVO.getCategoryIds()));
            categoryIds.addAll(convertList(categoryChildren, ProductCategoryDO::getId));
        }
        // 分页查询
        return productSpuMapper.selectPage(pageReqVO, categoryIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpuStock(Map<Long, Integer> stockIncrCounts) {
        stockIncrCounts.forEach((id, incCount) -> productSpuMapper.updateStock(id, incCount));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpuStatus(ProductSpuUpdateStatusReqVO updateReqVO) {
        // 校验存在
        validateSpuExists(updateReqVO.getId());
        // TODO 芋艿：【可选】参与活动中的商品，不允许下架？？？

        // 更新状态
        ProductSpuDO productSpuDO = productSpuMapper.selectById(updateReqVO.getId()).setStatus(updateReqVO.getStatus());
        productSpuMapper.updateById(productSpuDO);
    }

    @Override
    public Map<Integer, Long> getTabsCount() {
        Map<Integer, Long> counts = Maps.newLinkedHashMapWithExpectedSize(5);
        // 查询销售中的商品数量
        counts.put(ProductSpuPageReqVO.FOR_SALE,
                productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.ENABLE.getStatus()));
        // 查询仓库中的商品数量
        counts.put(ProductSpuPageReqVO.IN_WAREHOUSE,
                productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.DISABLE.getStatus()));
        // 查询售空的商品数量
        counts.put(ProductSpuPageReqVO.SOLD_OUT,
                productSpuMapper.selectCount(ProductSpuDO::getStock, 0));
        // 查询触发警戒库存的商品数量
        counts.put(ProductSpuPageReqVO.ALERT_STOCK,
                productSpuMapper.selectCount());
        // 查询回收站中的商品数量
        counts.put(ProductSpuPageReqVO.RECYCLE_BIN,
                productSpuMapper.selectCount(ProductSpuDO::getStatus, ProductSpuStatusEnum.RECYCLE.getStatus()));
        return counts;
    }

    @Override
    public Long getSpuCountByCategoryId(Long categoryId) {
        return productSpuMapper.selectCount(ProductSpuDO::getCategoryId, categoryId);
    }

}
